﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SudukuSolver_Mvvm.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Windows.Input;
using SudukuSolver_Mvvm.Models;

namespace SudukuSolver_Mvvm.ViewModels;

public partial class MainWindowViewModel : ObservableObject
{
    public static MainWindowViewModel Instance;
    public SudukuViewModel SudukuViewModel { get; set; }

    [ObservableProperty]
    private List<Level> levels = Enum.GetValues<Level>().ToList();

    [ObservableProperty]
    private List<string> language = new List<string>() { "中文", "英文" };

    [ObservableProperty]
    private List<string> theme = new List<string>() { "明亮", "黑暗" };

    /// <summary>
    /// 是否锁定数独，空的数独是不锁定的，填充内容后就锁定
    /// </summary>
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(SolveCommand))]
    [NotifyCanExecuteChangedFor(nameof(ExampleCommand))]
    private bool lockSuduku = false;

    /// <summary>
    /// 是否是测试模式
    /// </summary>
    [ObservableProperty]
    private bool isTestMode = false;

    #region 与数独计算相关的属性

    /// <summary>
    /// 多线程计算数独
    /// </summary>
    public Task SolveTask { get; set; }
    public CancellationTokenSource SolveCancel { get; set; } = new CancellationTokenSource();
    public ManualResetEvent SolveReset { get; set; } = new ManualResetEvent(true);
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(StopCommand))]
    [NotifyCanExecuteChangedFor(nameof(ExampleCommand))]
    SolveState solveState = SolveState.Stop;

    #endregion

    public MainWindowViewModel()
    {
        MainWindowViewModel.Instance = this;
        SudukuViewModel = new SudukuViewModel(GetExamples.GetRandom(Level.简单));
        LockSuduku = true;
    }

    #region 命令
    /// <summary>
    /// 停止，停止计算的命令，受属性 SolveState 的影响，非计算状态不需要停止
    /// </summary>
    [RelayCommand(CanExecute = nameof(CanStop))]
    private void Stop()
    {
        // 必须先继续这个线程，才能让线程执行到取消标记点
        // 否则他还在暂停点等着，不会运行取消的代码
        SolveReset.Set();
        SolveCancel.Cancel();

        SolveState = SolveState.Stop;
    }
    private bool CanStop()
    {
        return SolveState == SolveState.Solving || SolveState == SolveState.Pause;
    }

    /// <summary>
    /// 关闭，关闭窗口
    /// </summary>
    [RelayCommand]
    private void Close() => Environment.Exit(0);

    /// <summary>
    /// 示例，设置数独案例，受 SolveState 影响，计算状态不能设置
    /// </summary>
    /// <param name="parameter"></param>
    [RelayCommand(CanExecute = nameof(CanExample))]
    private void Example(object parameter)
    {
        if (parameter is Level level)
        {
            SudukuViewModel.SetNewSuduku(GetExamples.GetRandom(level));
            LockSuduku = true;
        }
    }
    private bool CanExample()
    {
        return !CanStop(); // 运行中不能设置新的数独
    }

    /// <summary>
    /// 计算，计算数独
    /// </summary>
    [RelayCommand(CanExecute = nameof(CanSolve))]
    private void Solve()
    {
        switch (SolveState)
        {
            case SolveState.Solving:
                // 如果是在计算中，那就暂停
                SolveReset.Reset();
                SolveState = SolveState.Pause;
                return;
            case SolveState.Stop:
                //如果没有开始，那就开始，并将状态设置为计算中
                SolveState = SolveState.Solving;

                SolveCancel = new CancellationTokenSource(); // 已经取消的任务，要想重新开始需要新建一个cts
                SolveReset = new ManualResetEvent(true);
                SolveTask = new Task(() => SudukuViewModel.Start(), SolveCancel.Token);
                SolveTask.Start();
                break;
            case SolveState.Pause:
                // 如果使暂停，那就继续计算
                SolveState = SolveState.Solving;
                SolveReset.Set();
                break;
            default:
                break;
        }

    }
    private bool CanSolve()
    {
        // 只有存在数独，且锁定状态才可以计算
        if (SudukuViewModel == null || !LockSuduku)
        {
            return false;
        }
        return true;
    }

    /// <summary>
    /// 清空数独
    /// </summary>
    [RelayCommand(CanExecute = nameof(CanSolve))]
    private void Clean()
    {
        SudukuViewModel.Resume();
    }
    #endregion
}